home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-07-03 | 6.8 KB | 202 lines | [TEXT/R*ch] |
- (* Date -- 1995-07-03 *)
-
- datatype weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
-
- datatype month
- = Jan | Feb | Mar | Apr | May | Jun
- | Jul | Aug | Sep | Oct | Nov | Dec
-
- datatype date = DATE of {
- year : int, (* e.g. 1995 *)
- month : month,
- day : int, (* 1-31 *)
- hour : int, (* 0-23 *)
- minute : int, (* 0-59 *)
- second : int, (* 0-61 (allowing for leap seconds) *)
- wday : weekday option,
- yday : int option, (* 0-365 *)
- isDst : bool option (* daylight savings time in force *)
- }
-
- exception Date
-
- local
- type tmoz = {tm_hour : int,
- tm_isdst : int, (* 0 = no, 1 = yes, ~1 = don't know *)
- tm_mday : int,
- tm_min : int,
- tm_mon : int,
- tm_sec : int,
- tm_wday : int,
- tm_yday : int,
- tm_year : int
- }
-
- prim_val getlocaltime_ : real -> tmoz = 1 "sml_localtime";
- prim_val getunivtime_ : real -> tmoz = 1 "sml_gmtime";
- prim_val mktime_ : tmoz -> real = 1 "sml_mktime";
-
- prim_val asctime_ : tmoz -> string = 1 "sml_asctime";
- prim_val strftime_ : string -> tmoz -> string = 2 "sml_strftime";
-
- val toweekday = fn 0 => Sun | 1 => Mon | 2 => Tue | 3 => Wed
- | 4 => Thu | 5 => Fri | 6 => Sat
- | _ => raise Fail "Internal error: Date.toweekday";
- val fromwday = fn Sun => 0 | Mon => 1 | Tue => 2 | Wed => 3
- | Thu => 4 | Fri => 5 | Sat => 6;
- val tomonth = fn 0 => Jan | 1 => Feb | 2 => Mar | 3 => Apr
- | 4 => May | 5 => Jun | 6 => Jul | 7 => Aug
- | 8 => Sep | 9 => Oct | 10 => Nov | 11 => Dec
- | _ => raise Fail "Internal error: Date.tomonth";
- val frommonth = fn Jan => 0 | Feb => 1 | Mar => 2 | Apr => 3
- | May => 4 | Jun => 5 | Jul => 6 | Aug => 7
- | Sep => 8 | Oct => 9 | Nov => 10 | Dec => 11;
-
- fun tmozToDate {tm_hour, tm_isdst, tm_mday, tm_min, tm_mon, tm_sec,
- tm_wday, tm_yday, tm_year} =
- DATE {year = tm_year + 1900, month = tomonth tm_mon,
- day = tm_mday, hour = tm_hour, minute = tm_min,
- second = tm_sec, wday = SOME (toweekday tm_wday),
- yday = SOME tm_yday,
- isDst = case tm_isdst of 0 => SOME false
- | 1 => SOME true
- | _ => NONE}
-
- fun okDate (DATE {year, month, day, hour, minute, second, yday, ...}) =
- let fun leap y =
- y rem 4 = 0 andalso y rem 100 <> 0 orelse y rem 400 = 0;
- val mthdays = fn Jan => 31 | Feb => if leap year then 29 else 28
- | Mar => 31 | Apr => 30 | May => 31 | Jun => 30
- | Jul => 31 | Aug => 31 | Sep => 30 | Oct => 31
- | Nov => 30 | Dec => 31;
- val yeardays = if leap year then 366 else 365
- in
- 1900 <= year
- andalso 1 <= day andalso day <= mthdays month
- andalso 0 <= hour andalso hour <= 23
- andalso 0 <= minute andalso minute <= 59
- andalso 0 <= second andalso second <= 61 (* leap seconds *)
- andalso case yday of
- NONE => true
- | SOME yd => 0 <= yd andalso yd < yeardays
- end;
-
- fun dateToTmoz (dt as DATE {year, month, day, hour, minute, second,
- wday, yday, isDst}) =
- if okDate dt then
- {tm_hour = hour, tm_mday = day, tm_min = minute,
- tm_mon = frommonth month, tm_sec = second,
- tm_year = year - 1900,
- tm_isdst = case isDst of SOME false=>0 | SOME true=>1 | NONE=> ~1,
- tm_wday = case wday of SOME w => fromwday w | NONE => 0,
- tm_yday = case yday of SOME y => y | NONE => 0}
- else
- raise Date;
-
- in
-
- fun fromTime t = tmozToDate (getlocaltime_ (Time.timeToReal t));
-
- fun fromUTC t = tmozToDate (getunivtime_ (Time.timeToReal t));
-
- (* The following implements conversion from a local date to
- a Time.time. It IGNORES wday and yday. *)
-
- fun toTime date =
- let val clock = mktime_ (dateToTmoz date)
- in
- if clock < 0.0 then raise Date
- else Time.realToTime clock
- end;
-
- fun toString date =
- String.substring(asctime_ (dateToTmoz date), 0, 24)
- handle Fail _ => raise Date
- | Subscript => raise (Fail "Date.toString: internal error");
-
- fun fmt fmtstr date =
- (strftime_ fmtstr (dateToTmoz date))
- handle Fail _ => raise Date
-
- (* To scan dates in the format "Wed Mar 08 19:06:45 1995" *)
-
- fun scan {getc : 'a -> (char * 'a) option} source =
- let exception BadFormat
- fun decval c = Char.ord c - 48
- fun char wanted src =
- case getc src of
- NONE => raise BadFormat
- | SOME (c, rest) => if c=wanted then rest
- else raise BadFormat
- fun getndig 0 res src = (res, src)
- | getndig n res src =
- case getc src of
- NONE => raise BadFormat
- | SOME (c, rest) =>
- if Char.isDigit c then
- getndig (n-1) (10 * res + decval c) rest
- else
- raise BadFormat
- fun getnalf 0 res src = (String.implode (List.rev res), src)
- | getnalf n res src =
- case getc src of
- NONE => raise BadFormat
- | SOME (c, rest) =>
- if Char.isAlpha c then getnalf (n-1) (c :: res) rest
- else raise BadFormat
-
- val get2dig = getndig 2 0
- val get4dig = getndig 4 0
- val get3alf = getnalf 3 []
-
- val getMonth = fn "Jan" => Jan | "Feb" => Feb | "Mar" => Mar
- | "Apr" => Apr | "May" => May | "Jun" => Jun
- | "Jul" => Jul | "Aug" => Aug | "Sep" => Sep
- | "Oct" => Oct | "Nov" => Nov | "Dec" => Dec
- | _ => raise BadFormat
- val getWday = fn "Sun" => Sun | "Mon" => Mon | "Tue" => Tue
- | "Wed" => Wed | "Thu" => Thu | "Fri" => Fri
- | "Sat" => Sat | _ => raise BadFormat
- in
- let val src = StringCvt.skipWS {getc = getc} source
- val (wday, src) = get3alf src
- val src = char #" " src
- val (month, src) = get3alf src
- val src = char #" " src
- val (day, src) = get2dig src
- val src = char #" " src
- val (hour, src) = get2dig src
- val src = char #":" src
- val (min, src) = get2dig src
- val src = char #":" src
- val (sec, src) = get2dig src
- val src = char #" " src
- val (year, rest) = get4dig src
- in SOME (DATE {year = year, month = getMonth month,
- day = day, hour = hour, minute = min,
- second = sec, wday = SOME (getWday wday),
- yday = NONE, isDst = NONE}, rest)
- end
- handle BadFormat => NONE
- end;
-
- fun fromString s = StringCvt.scanString scan s
-
- fun compare
- (DATE {year=y1,month=mo1,day=d1,hour=h1,minute=mi1,second=s1, ...},
- DATE {year=y2,month=mo2,day=d2,hour=h2,minute=mi2,second=s2, ...}) =
- let fun cmp(v1, v2, cmpnext) =
- if v1 < v2 then LESS
- else if v1 > v2 then GREATER
- else (* EQUAL *) cmpnext ()
- in
- cmp(y1, y2,
- fn _ => cmp(frommonth mo1, frommonth mo2,
- fn _ => cmp(d1, d2,
- fn _ => cmp(h1, h2,
- fn _ => cmp(mi1, mi2,
- fn _ => cmp(s1, s2,
- fn _ => EQUAL))))))
- end
- end
-